package cn.edu.sgu.www.mhxysy.service.potency.impl;

import cn.edu.sgu.www.mhxysy.consts.CustomMessages;
import cn.edu.sgu.www.mhxysy.dto.potency.PotencyFruitDTO;
import cn.edu.sgu.www.mhxysy.dto.potency.PotencyFruitMoveDTO;
import cn.edu.sgu.www.mhxysy.entity.except.Property;
import cn.edu.sgu.www.mhxysy.entity.exp.RoleExp;
import cn.edu.sgu.www.mhxysy.entity.potency.PotencyFruit;
import cn.edu.sgu.www.mhxysy.entity.potency.PotencyFruitSchema;
import cn.edu.sgu.www.mhxysy.enums.OpenStatus;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import cn.edu.sgu.www.mhxysy.formatter.NumberFormatter;
import cn.edu.sgu.www.mhxysy.mapper.except.PropertyMapper;
import cn.edu.sgu.www.mhxysy.mapper.exp.RoleExpMapper;
import cn.edu.sgu.www.mhxysy.mapper.potency.PotencyFruitMapper;
import cn.edu.sgu.www.mhxysy.mapper.potency.PotencyFruitPatternMapper;
import cn.edu.sgu.www.mhxysy.mapper.potency.PotencyFruitSchemaMapper;
import cn.edu.sgu.www.mhxysy.pager.Pager;
import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import cn.edu.sgu.www.mhxysy.service.potency.PotencyFruitService;
import cn.edu.sgu.www.mhxysy.util.MathUtils;
import cn.edu.sgu.www.mhxysy.util.ObjectUtils;
import cn.edu.sgu.www.mhxysy.vo.except.PropertyVO;
import cn.edu.sgu.www.mhxysy.vo.potency.PotencyFruitPropertyVO;
import cn.edu.sgu.www.mhxysy.vo.potency.PotencyFruitVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author 沐雨橙风ιε
 * @version 1.0
 */
@Service
public class PotencyFruitServiceImpl implements PotencyFruitService {

    private final RoleExpMapper roleExpMapper;
    private final PropertyMapper propertyMapper;
    private final PotencyFruitMapper potencyFruitMapper;
    private final PotencyFruitSchemaMapper potencyFruitSchemaMapper;
    private final PotencyFruitPatternMapper potencyFruitPatternMapper;

    @Autowired
    public PotencyFruitServiceImpl(
            RoleExpMapper roleExpMapper,
            PropertyMapper propertyMapper,
            PotencyFruitMapper potencyFruitMapper,
            PotencyFruitSchemaMapper potencyFruitSchemaMapper,
            PotencyFruitPatternMapper potencyFruitPatternMapper) {
        this.roleExpMapper = roleExpMapper;
        this.propertyMapper = propertyMapper;
        this.potencyFruitMapper = potencyFruitMapper;
        this.potencyFruitSchemaMapper = potencyFruitSchemaMapper;
        this.potencyFruitPatternMapper = potencyFruitPatternMapper;
    }

    @Override
    public void move(PotencyFruitMoveDTO potencyFruitMoveDTO) {
        Integer orignId = potencyFruitMoveDTO.getOrignId();
        Integer targetId = potencyFruitMoveDTO.getTargetId();

        if (targetId != null) { // 移动到非空白位置
            PotencyFruit target = potencyFruitMapper.selectById(targetId);

            if (!target.getLocation().equals(potencyFruitMoveDTO.getLocation())) {
                throw new GlobalException(ResponseCode.CONFLICT, CustomMessages.OPERATE_FAILURE);
            }

            // 交换两个潜能果的属性
            PotencyFruit orign = potencyFruitMapper.selectById(orignId);

            Integer propertyId = target.getPropertyId();

            target.setPropertyId(orign.getPropertyId());

            potencyFruitMapper.updateById(target);

            orign.setPropertyId(propertyId);

            potencyFruitMapper.updateById(orign);
        } else { // 移动到空白位置
            // 修改潜能果位置
            UpdateWrapper<PotencyFruit> updateWrapper = new UpdateWrapper<>();

            updateWrapper.eq("id", orignId);
            updateWrapper.set("location", potencyFruitMoveDTO.getLocation());

            potencyFruitMapper.update(updateWrapper.getEntity(), updateWrapper);
        }
    }

    @Override
    public void renewal(Integer fruitId, Integer propertyId) {
        PotencyFruit potencyFruit = potencyFruitMapper.selectById(fruitId);

        if (potencyFruit == null) {
            throw new GlobalException(ResponseCode.BAD_REQUEST, "操作失败，潜能果不存在！");
        }

        // 理论上不会出现这种情况
        if (potencyFruit.getPropertyId().equals(propertyId)) {
            throw new GlobalException(ResponseCode.BAD_REQUEST, "待转换属性与当前潜能果的属性相同！");
        }

        potencyFruit.setPropertyId(propertyId);

        potencyFruitMapper.updateById(potencyFruit);
    }

    @Override
    public void returnFruit(Integer fruitId) {
        PotencyFruit potencyFruit = potencyFruitMapper.selectById(fruitId);

        if (potencyFruit == null) {
            throw new GlobalException(ResponseCode.BAD_REQUEST, "操作失败，潜能果不存在！");
        }

        String roleId = potencyFruit.getRoleId();

        // 查询当前开启的潜能果方案的掐能果数量
        QueryWrapper<PotencyFruit> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("role_id", roleId);
        queryWrapper.eq("schema_id", potencyFruit.getSchemaId());

        Long count = potencyFruitMapper.selectCount(queryWrapper);

        if (count == 0) {
            throw new GlobalException(ResponseCode.BAD_REQUEST, "操作失败，没有潜能果可返还！");
        }

        // 得到当前角色最后一颗潜能果的兑换经验
        int exchangeExp = computeExchangeExp(Math.toIntExact(count));

        QueryWrapper<RoleExp> queryWrapper1 = new QueryWrapper<>();

        queryWrapper1.eq("role_id", roleId);

        RoleExp roleExp = roleExpMapper.selectOne(queryWrapper1);

        if (roleExp != null) {
            // 增加角色经验
            roleExp.setExp(exchangeExp + roleExp.getExp());

            roleExpMapper.updateById(roleExp);
        }

        potencyFruitMapper.deleteById(fruitId);
    }

    @Override
    public void exchange(String roleId) {
        QueryWrapper<RoleExp> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("role_id", roleId);

        RoleExp roleExp = roleExpMapper.selectOne(queryWrapper);

        if (roleExp != null) {
            Long currentExp = roleExp.getExp();

            if (currentExp == 0) {
                throw new GlobalException(ResponseCode.CONFLICT, "您当前没有经验可用于兑换！");
            }

            // 查询角色当前潜能果个数
            Map<String, Object> columnMap = new HashMap<>();

            columnMap.put("role_id", roleId);

            List<PotencyFruit> list = potencyFruitMapper.selectByMap(columnMap);

            // 计算兑换潜能果需要的经验
            int exchangeExp = computeExchangeExp(list.size() + 1);

            if (currentExp >= exchangeExp) {
                // 1、扣除角色经验
                roleExp.setExp(currentExp - exchangeExp);

                roleExpMapper.updateById(roleExp);

                // 2、添加潜能果
                // 查询附加属性
                columnMap.clear();
                columnMap.put("type", 2);

                List<Property> properties = propertyMapper.selectByMap(columnMap);

                PotencyFruit potencyFruit = new PotencyFruit();

                potencyFruit.setRoleId(roleId);

                /*
                 * 设置随机属性
                 */
                int random = MathUtils.random(0, properties.size() - 1);

                potencyFruit.setPropertyId(properties.get(random).getId());

                /*
                 * 设置随机位置
                 */
                List<Integer> locations = list.stream().map(new Function<PotencyFruit, Integer>() {
                    @Override
                    public Integer apply(PotencyFruit potencyFruit) {
                        return potencyFruit.getLocation();
                    }
                }).collect(Collectors.toList());

                // 删除已经有潜能果的位置
                List<Integer> indexs = new ArrayList<>();

                for (int index = 1; index <= 79; index++) {
                    indexs.add(index);
                }

                indexs.removeAll(locations);

                random = MathUtils.random(0, indexs.size() - 1);

                potencyFruit.setLocation(indexs.get(random));

                /*
                 * 设置潜能果方案
                 */
                // 查询角色当前开启的潜能果方案
                QueryWrapper<PotencyFruitSchema> queryWrapper1 = new QueryWrapper<>();

                queryWrapper1.eq("role_id", roleId);
                queryWrapper1.eq("open_status", OpenStatus.OPEN.getValue());

                PotencyFruitSchema potencyFruitSchema = potencyFruitSchemaMapper.selectOne(queryWrapper1);

                if (potencyFruitSchema == null) {
                    throw new GlobalException(ResponseCode.CONFLICT, "您当前未开启潜能果方案！");
                }

                potencyFruit.setSchemaId(potencyFruitSchema.getId());

                potencyFruitMapper.insert(potencyFruit);
            } else {
                String format = NumberFormatter.format(exchangeExp);
                String errorMessage = "您的经验不足以兑换下一个潜能果（需要<span class='red'>" + format + "<span>经验）";

                throw new GlobalException(ResponseCode.CONFLICT, errorMessage);
            }
        }
    }

    @Override
    public void insert(PotencyFruitDTO potencyFruitDTO) {
        PotencyFruit potencyFruit = toEntity(potencyFruitDTO);

        potencyFruit.setId(null);

        potencyFruitMapper.insert(potencyFruit);
    }

    @Override
    public void deleteById(Integer id) {
        potencyFruitMapper.deleteById(id);
    }

    @Override
    public void updateById(PotencyFruitDTO potencyFruitDTO) {
        ObjectUtils.requireNonNull(potencyFruitDTO.getId(), CustomMessages.ID_NOT_NULL);

        PotencyFruit potencyFruit = toEntity(potencyFruitDTO);

        potencyFruitMapper.updateById(potencyFruit);
    }

    @Override
    public PotencyFruitVO selectDetail(Integer id) {
        return potencyFruitMapper.selectDetail(id);
    }

    @Override
    public Integer selectExchangeExp(String roleId) {
        // 查询角色当前潜能果个数
        QueryWrapper<PotencyFruit> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("role_id", roleId);

        Long count = potencyFruitMapper.selectCount(queryWrapper);

        // 计算兑换经验
        int n = Math.toIntExact(++ count);

        return computeExchangeExp(n);
    }

    @Override
    public Page<PotencyFruit> selectByPage(Pager<PotencyFruit> pager) {
        Page<PotencyFruit> page = Pager.ofPage(pager);

        return potencyFruitMapper.selectPage(page, null);
    }

    @Override
    public List<PotencyFruit> selectList(String roleId, Integer schemaId) {
        QueryWrapper<PotencyFruit> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("role_id", roleId);
        queryWrapper.eq("schema_id", schemaId);

        return potencyFruitMapper.selectList(queryWrapper);
    }

    @Override
    public List<PotencyFruitVO> selectDetails(String roleId, Integer schemaId) {
        return potencyFruitMapper.selectDetails(roleId, schemaId);
    }

    @Override
    public List<PotencyFruitPropertyVO> selectAdditiveProperties(String roleId) {
        List<PropertyVO> properties = potencyFruitMapper.selectProperty(roleId);

        PotencyFruitPropertyVO potencyFruitProperty = new PotencyFruitPropertyVO();

        potencyFruitProperty.setName("潜能果加成");
        potencyFruitProperty.setList(properties);

        // 构建返回结果对象
        List<PotencyFruitPropertyVO> list = potencyFruitPatternMapper.selectProperty(roleId);

        list.add(0, potencyFruitProperty);

        return list;
    }

    private PotencyFruit toEntity(PotencyFruitDTO potencyFruitDTO) {
        Integer id = potencyFruitDTO.getId();
        String roleId = potencyFruitDTO.getRoleId();
        Integer location = potencyFruitDTO.getLocation();

        QueryWrapper<PotencyFruit> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("role_id", roleId);
        queryWrapper.eq("location", location);

        queryWrapper.ne(id != null, "id", id);

        Long count = potencyFruitMapper.selectCount(queryWrapper);

        if (count > 0) {
            throw new GlobalException(ResponseCode.CONFLICT, "该位置已经有潜能果了！");
        }

        PotencyFruit potencyFruit = new PotencyFruit();

        potencyFruit.setId(id);
        potencyFruit.setRoleId(roleId);
        potencyFruit.setLocation(location);
        potencyFruit.setSchemaId(potencyFruitDTO.getSchemaId());
        potencyFruit.setPropertyId(potencyFruitDTO.getPropertyId());

        return potencyFruit;
    }

    /**
     * 计算兑换经验
     * @param n 第几颗潜能果
     * @return 兑换需要的经验
     */
    private int computeExchangeExp(int n) {
        if (n == 1) { // 兑换第一颗潜能果需要3000万经验
            return 30_000_000; // 3千万
        } else if (n <= 60) { // 兑换第n颗潜能果需要的经验逐步升高
            // 求等差数列第n项：(n × a₁ + (n - 1 ) × d)
            int a1 = 3000; // 等差数列的首项a₁：兑换第一颗潜能果需要的经验（单位：/万）
            int d = 1000; // 等差数列的公差d（单位：/万）

            int an = (a1 + (n - 1) * d); // aₙ = a₁ + (n - 1 ) × d

            return an * 1_0000; // 转为万
        }

        return 630_000_000; // 6.3亿、6.3e9
    }

}